package commodity

import (
	"end/config"
	"end/entry"
	"end/httpEntry"
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
	"time"
)

type Request struct {
	Title    string `json:"title" binding:"required"`
	FirstImg string `json:"first_img" binding:"required"`
	Integral int    `json:"integral" binding:"required"`
	Num      int    `json:"num" binding:"required"`
	Message  string `json:"message" binding:"required"`
}

type AllRequest struct {
	Status int `json:"status" binding:"required"`
	Page   int `json:"page" binding:"required"`
}

type Dto struct {
	entry.Commodity
	Business entry.Business `json:"business"`
}

func (Dto) TableName() string {
	return "commodity"
}

type ShopRequest struct {
	CommodityId string `json:"commodityid" binding:"required"`
}

// UploadCommodity 上传商品
func UploadCommodity(r *gin.Engine) {
	r.POST("/commodity/upload", httpEntry.LoginMiddleware(), httpEntry.BusinessMiddleware(), func(context *gin.Context) {
		var request Request
		err := context.ShouldBind(&request)
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		db := config.GetDb()
		userinfo := context.MustGet("userinfo").(config.UserInfo)
		var business entry.Business
		result := db.Where("id = ?", userinfo.Id).First(&business)
		if result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10014,
				Error: httpEntry.ERROR10014,
			})
			return
		}
		if business.Status != httpEntry.STATUS2 {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10004,
				Error: httpEntry.ERROR10004,
			})
			return
		}
		if err != nil {
			return
		}
		commodity := entry.Commodity{
			Title:      request.Title,
			BusinessID: userinfo.Id,
			Integral:   request.Integral,
			Num:        request.Num,
			FirstImg:   request.FirstImg,
			Message:    request.Message,
			CreateTime: time.Now(),
		}
		commodity.Status = httpEntry.STATUS2
		result = db.Create(&commodity)
		if result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10005,
				Error: httpEntry.ERROR10005,
			})
			return
		}
		context.JSON(http.StatusOK, gin.H{
			"code":      200,
			"message":   "添加成功",
			"commodity": commodity,
		})
	})
}

// UpdateCommodity 修改信息
func UpdateCommodity(r *gin.Engine) {
	r.POST("/commodity/update/:id", httpEntry.LoginMiddleware(), httpEntry.BusinessMiddleware(), func(context *gin.Context) {
		commodityIdStr := context.Param("id")
		// 将用户ID转换为整数
		var commodityId int
		_, err := fmt.Sscanf(commodityIdStr, "%d", &commodityId)
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		var request Request
		err = context.BindJSON(&request)
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		db := config.GetDb()
		userinfo := context.MustGet("userinfo").(config.UserInfo)
		toMap, err := config.UpdateToMap(&request)
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10014,
				Error: httpEntry.ERROR10014,
			})
			return
		}
		config.Lock()
		defer config.Unlock()
		if err := db.Model(&entry.Commodity{}).Where("businessid = ?", userinfo.Id).Updates(toMap).Error; err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10014,
				Error: httpEntry.ERROR10014,
			})
			return
		}
		context.JSON(http.StatusOK, gin.H{
			"code":    200,
			"message": "修改成功",
		})
	})
}

// DelCommodity 删除
func DelCommodity(r *gin.Engine) {
	r.POST("/commodity/del/:id", httpEntry.LoginMiddleware(), httpEntry.BusinessMiddleware(), func(context *gin.Context) {
		commodityIdStr := context.Param("id")
		// 将用户ID转换为整数
		var commodityId int
		_, err := fmt.Sscanf(commodityIdStr, "%d", &commodityId)
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		db := config.GetDb()
		var commodity entry.Commodity
		config.Lock()
		defer config.Unlock()
		if result := db.Where("id = ?", commodityId).First(&commodity); result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10005,
				Error: httpEntry.ERROR10005,
			})
			return
		}

		if userinfo := context.MustGet("userinfo").(config.UserInfo); commodity.BusinessID != userinfo.Id {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10011,
				Error: httpEntry.ERROR10011,
			})
			return
		}
		// 删除商品
		result := db.Where("id = ?", commodityId).Delete(commodity)
		if result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10005,
				Error: httpEntry.ERROR10005,
			})
			return
		}
		context.JSON(http.StatusOK, gin.H{
			"code":    200,
			"message": "删除",
		})
	})
}

// AllCommodity 热门商品
func AllCommodity(r *gin.Engine) {
	r.GET("/commodity/all/:page", httpEntry.LoginMiddleware(), func(context *gin.Context) {
		pageStr := context.Param("page")
		page, err := strconv.Atoi(pageStr)
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		db := config.GetDb()
		var commodities []entry.Commodity
		result := db.Model(&entry.Commodity{}).
			Offset((page - 1) * 30).
			Limit(30).
			Order("createtime desc").
			Find(&commodities)
		if result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10005,
				Error: httpEntry.ERROR10005,
			})
			return
		}
		context.JSON(http.StatusOK, gin.H{
			"code":    200,
			"message": "获取成功",
			"data":    commodities,
		})
	})
}

// DetailsCommodity 商品详情，获取商品
func DetailsCommodity(r *gin.Engine) {
	r.GET("/commodity/details/:id", httpEntry.LoginMiddleware(), func(context *gin.Context) {
		idStr := context.Param("id")
		id, err := strconv.Atoi(idStr)
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
		}
		var commodity Dto
		db := config.GetDb()
		result := db.Preload("Business").
			Where("commodity.id = ?", id).
			Find(&commodity)
		if result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10014,
				Error: httpEntry.ERROR10014,
			})
			return
		}
		context.JSON(http.StatusOK, gin.H{
			"code":    200,
			"message": "成功",
			"data":    commodity,
		})
	})
}

// ShopCommodity 购买商品
func ShopCommodity(r *gin.Engine) {
	r.POST("/shop/commodity/:commodityid", httpEntry.LoginMiddleware(), func(context *gin.Context) {
		// 获取用户信息，获取订单信息
		commodityid := context.Param("commodityid")
		if commodityid == "" {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		userinfo := context.MustGet("userinfo").(config.UserInfo)
		db := config.GetDb()
		var user entry.User
		result := db.Where("id = ?", userinfo.Id).First(&user)
		if result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10014,
				Error: httpEntry.ERROR10014,
			})
			return
		}
		// 开始查询
		config.Lock()
		defer config.Unlock()
		var commodity entry.Commodity
		result = db.Where("id = ? and status = ?", commodityid, httpEntry.STATUS2).First(&commodity)
		if result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10004,
				Error: httpEntry.ERROR10005,
			})
			return
		}
		if commodity.Num <= 0 {
			// 库存不够
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10016,
				Error: httpEntry.ERROR10016,
			})
			return
		}
		if commodity.Status != config.STATUS2 {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10027,
				Error: httpEntry.ERROR10027,
			})
			return
		}
		if user.Integral < commodity.Integral {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10015,
				Error: httpEntry.ERROR10015,
			})
			return
		}
		// 更新部分也可以直接db.Updates(&user)，但是这样子里面的空值也会更新上去，所以不推荐
		// 更新用户积分
		user.Integral -= commodity.Integral
		if err := db.Model(&user).Updates(map[string]interface{}{"integral": user.Integral}).Error; err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10014,
				Error: httpEntry.ERROR10014,
			})
			return
		}

		// 更新商品数量
		commodity.Num -= 1
		if err := db.Model(&commodity).Updates(map[string]interface{}{"num": commodity.Num}).Error; err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10014,
				Error: httpEntry.ERROR10014,
			})
			return
		}

		// 创建订单
		order := entry.Order{
			CommodityID: commodity.ID,
			UserID:      user.ID,
			Status:      httpEntry.STATUS1,
			Businessid:  commodity.BusinessID,
			UpdateTime:  time.Now(),
			CreateTime:  time.Now(),
		}
		if err := db.Create(&order).Error; err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10014,
				Error: httpEntry.ERROR10014,
			})
			return
		}
		// 返回结构
		context.JSON(http.StatusOK, gin.H{
			"code":    200,
			"message": "购买成功",
			"data":    order,
		})
	})
}

type StatusCommodityRequest struct {
	Id     int `json:"id" binding:"required"`
	Status int `json:"status" binding:"required"`
}

// StatusCommodity 商品下架上架
func StatusCommodity(r *gin.Engine) {
	r.POST("/commodity/status", httpEntry.LoginMiddleware(), httpEntry.BusinessMiddleware(), func(context *gin.Context) {
		var statusCommodityRequest StatusCommodityRequest
		err := context.ShouldBind(&statusCommodityRequest)
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		db := config.GetDb()
		// 修改商品状态
		var commodity entry.Commodity
		// 判断商品是否存在
		if result := db.Where("id = ?", statusCommodityRequest.Id).First(&commodity); result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10005,
				Error: httpEntry.ERROR10005,
			})
			return
		}
		// 判断是否商家拥有
		if userinfo := context.MustGet("userinfo").(config.UserInfo); commodity.BusinessID != userinfo.Id {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10011,
				Error: httpEntry.ERROR10011,
			})
			return
		}
		// 修改商品状态
		config.Lock()
		defer config.Unlock()
		db.Model(entry.Commodity{}).Where("id = ?", statusCommodityRequest.Id).Updates(map[string]interface{}{
			"status": statusCommodityRequest.Status,
		})
		context.JSON(http.StatusOK, gin.H{
			"code":    200,
			"message": "修改成功",
		})
	})
}
